package com.ikun.admin.websocket.server;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ikun.admin.websocket.config.WebSocketConfig;
import com.ikun.admin.websocket.constant.WebSocketConstant;
import com.ikun.admin.websocket.message.UserMapSessionData;
import com.ikun.admin.websocket.message.WebSocketMessage;
import com.ikun.common.exception.MyException;
import com.ikun.starters.jwt.impl.TokenService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import static com.ikun.admin.websocket.constant.WebSocketConstant.WEBSOCKET_URL;

/**
 * @ClassName WebSocketServer
 * @Description:
 * @CreateDate: 2024/9/6 17:04
 */
@Slf4j
@Component
@ServerEndpoint(value = WEBSOCKET_URL, configurator = WebSocketConfig.class)
public class WebSocketServer {

    // 连接信息 userId-UserMapSessionData
    private static final Map<Long, UserMapSessionData> webSocketServerConnectionMap = new ConcurrentHashMap<>();

    // 保存数据的bean
    private IService service;

    private static TokenService tokenService;

    public static void init(ApplicationContext applicationContext) {

        //获取保存数据的bean
        log.info("初始化WebSocketServer:");
        tokenService = applicationContext.getBean(TokenService.class);
//        applicationContext.getBean("");
    }

    @OnOpen
    public void onOpen(Session session) {
        log.info("有新的连接加入:{}", session.getId());
        log.info("当前连接数:{}", webSocketServerConnectionMap.size());
        Long userId = this.getUseIdToSession(session);
        if (userId != null) {
            webSocketServerConnectionMap.put(userId, new UserMapSessionData(userId, session));
        }
    }

    @OnClose
    public void close(Session session) {
        log.info("有连接断开:{}", session.getId());
        Long userId = this.getUseIdToSession(session);
        webSocketServerConnectionMap.remove(userId);
    }

    @OnError
    public void onError(Session session, Throwable throwable) {
        Long userId = this.getUseIdToSession(session);
        log.info("连接断开异常id为:{}", userId);
        webSocketServerConnectionMap.remove(session.getId());
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("收到消息:{}", message);
        //todo 转发消息
        WebSocketMessage webSocketMessage = JSONObject.parseObject(message, WebSocketMessage.class);
        WebSocketMessage.Message sourceMessage = webSocketMessage.getMessage();
        Integer messageType = webSocketMessage.getMessageType();
        if (messageType == WebSocketConstant.MESSAGE_TYPE_USER) {
            Long from = webSocketMessage.getFrom();
            Long to = webSocketMessage.getTo();
            //校验token
            Boolean verifyToken = tokenService.verifyToken(webSocketMessage.getToken());
            if (!verifyToken) {
                throw new MyException("无效token");
            }
            if (from == null || to == null) {
                throw new MyException("发送方或接收方为空");
            }
            if (webSocketMessage.getMessage().getContent() != null) {
                this.sendTextMessage(to, webSocketMessage.getMessage().getContent());
            }
            if (webSocketMessage.getMessage().getFile() != null) {
                this.sendBinaryMessage(to, webSocketMessage.getMessage().getFile());
            }
        } else if (messageType == WebSocketConstant.MESSAGE_TYPE_SYS) {
            //系统消息
            Set<Long> ids = webSocketServerConnectionMap.keySet();
            this.sendGroupMessage(ids, sourceMessage.getContent());
        }

    }

    private Long getUseIdToSession(Session session) {
        return (Long) session.getUserProperties().get(WebSocketConstant.ONLINE_USER_KEY);
    }

    //发送文本消息
    private void sendTextMessage(Long toUserId, String message) {
        try {
            UserMapSessionData userMapSessionData = webSocketServerConnectionMap.get(toUserId);
            if (userMapSessionData != null) {
                Session session = userMapSessionData.getSession();
                session.getBasicRemote().sendText(message);
            }
        } catch (IOException e) {
            log.info("websocket文本消息转发异常:{}", e);
            throw new RuntimeException(e);
        }
    }

    // 发送文件消息
    private void sendBinaryMessage(Long toUserId, byte[] message) {
        try {
            UserMapSessionData userMapSessionData = webSocketServerConnectionMap.get(toUserId);
            if (userMapSessionData != null) {
                Session session = userMapSessionData.getSession();
                //转换为byte[]
                session.getBasicRemote().sendBinary(ByteBuffer.wrap(message));
            }
        } catch (IOException e) {
            log.error("websocket文件转发异常:{}", e);
            throw new RuntimeException(e);
        }

    }

    private void sendGroupMessage(Set<Long> userIds, String message) {

        webSocketServerConnectionMap.forEach((userId, userMapSessionData) -> {
            if (userIds.contains(userMapSessionData.getId())) {
                Long toUserId = userMapSessionData.getId();
                this.sendTextMessage(toUserId, message);
            }
        });
    }
}
